package com.danco.training.zaneuskaya.domain.service.storage;

import java.io.IOException;
import java.io.Serializable;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import org.apache.log4j.Logger;



import com.danco.training.zaneuskaya.cswworker.CSVReader;
import com.danco.training.zaneuskaya.cswworker.CSVSaver;
import com.danco.training.zaneuskaya.cswworker.Separator;
import com.danco.training.zaneuskaya.domain.comparator.BookComparatorByAlphabet;
import com.danco.training.zaneuskaya.domain.comparator.BookComparatorByPrice;
import com.danco.training.zaneuskaya.domain.comparator.BookComparatorByPublicationDate;
import com.danco.training.zaneuskaya.domain.comparator.BookComparatorByQuantity;
import com.danco.training.zaneuskaya.domain.comparator.BookComparatorByReceiptDate;
import com.danco.training.zaneuskaya.domain.entity.Book;
import com.danco.training.zaneuskaya.domain.entity.Claim;
import com.danco.training.zaneuskaya.domain.entity.storage.BookStorage;
import com.danco.training.zaneuskaya.domain.entity.storage.ClaimStorage;
import com.danco.training.zaneuskaya.property.PropertyAccess;




public class BookStorageService implements Serializable{

	
	/**
	 * 
	 */
	private static final long serialVersionUID = -2536598046985962659L;
	
	private BookStorage bookStorage;
	private ClaimStorage claimStorage ;
	public static final int MONTH_NUMBER = PropertyAccess.getIntProperty("months");
	public static final boolean EXECUTE_CLAIM = PropertyAccess.getBooleanProperty("setclaim");
	
	private BookComparatorByAlphabet bookComparatorByAlphabet = new BookComparatorByAlphabet(); 
	private BookComparatorByPublicationDate bookComparatorByPublicationDate = new BookComparatorByPublicationDate();
	private BookComparatorByPrice bookComparatorByPrice = new BookComparatorByPrice();
	private BookComparatorByQuantity bookComparatorByQuantity = new BookComparatorByQuantity();
	private BookComparatorByReceiptDate bookComparatorByReceiptDate = new BookComparatorByReceiptDate();

	
	private static final Logger logger = Logger.getLogger(BookStorageService.class);
	private static BookStorageService bookStorageSeviceInstance;
	
	
	
public BookStorageService() {
		
		this.bookStorage = BookStorage.getBookStorageInstance();
		this.claimStorage = ClaimStorage.getClaimStorageInstance();
	}



public Book getBookById(int id){
		
		for (Book b: bookStorage.getBooks()){
			if (b.getId() == id){
				logger.trace("Book is founded in Bookstorage by id");
				return b;
			}
			
		}
		logger.info("Book not founded in Bookstorage ");
		return null;
	}
	public List<Book> getBookList(){
		List<Book> res = new ArrayList<Book>(bookStorage.getBooks());
		
		logger.trace("Book list");

		return res;
	}
	
	public List<Integer> getBookListId(){
		List<Integer> res = new ArrayList<Integer>();
		for (Book b :bookStorage.getBooks()) {
			res.add(b.getId())	;			
				}
			
		
		return res;
	
	}
	
	public int generateUnexistedId(){
		int i = 1;
		while(getBookListId().contains(i)){
			i++;
		}
		return i;
	}
	
	public List<Book> getSomeMonthsUnsoldBooks(List<Book> books){
		List<Book> res = new ArrayList<Book>();
		for (Book b : books) {
			if (b.getReceiptDate().getMonth() - new Date().getMonth() >= MONTH_NUMBER) {
				if (b.getQuantity() > 0) {
					
					res.add(b);
					
				}
			}
		}
		logger.trace("Six months unsold books are founded");
		return res;
	
	}
	public List<Book> sortBooksByAlphabet(List<Book> books) {

		Collections.sort(books, bookComparatorByAlphabet);
		logger.trace("Books are sorted by alphabet");
		return books;
	}

	public List<Book> sortBooksByPublicationDate(List<Book> books) {

		Collections.sort(books,  bookComparatorByPublicationDate);
		logger.trace("Books are sorted by publication date");
		return books;
	}

	public List<Book> sortBooksByPrice(List<Book> books) {

		Collections.sort(books, bookComparatorByPrice);
		logger.trace("Books are sorted by price");
		return books;
	}

	public List<Book> sortBooksByAvailability(List<Book> books) {

		Collections.sort(books, bookComparatorByQuantity);
		logger.trace("Books are sorted by availability");

		return books;
	}

	public List<Book> sortUnsoldBooksByReceiptDate(List<Book> books) {
		List<Book> res = new ArrayList<Book>();
		res = getSomeMonthsUnsoldBooks(books);
			Collections.sort(res, bookComparatorByReceiptDate);
			logger.trace("Six munths unsold books are sorted by receipt date");

		
		return res;
	}

	public List<Book> sortUnsoldBooksByPrice(List<Book> books) {
		List<Book> res = new ArrayList<Book>();
		res = getSomeMonthsUnsoldBooks(books);
		Collections.sort(res, bookComparatorByPrice);
		logger.trace("Some months unsold books are sorted by price");

		return res;
	}
	public List<Book> getAvailableBooks(){
		List<Book> books = new ArrayList<Book>();
		for (Book book: books){
			if(book.isAvailable()){
				books.add(book);
			}
		}
		return books;
	}
	
	public List<Book> getNotAvailableBooks(){
		List<Book> books = new ArrayList<Book>();
		for (Book book: books){
			if(!book.isAvailable()){
				books.add(book);
			}
		}
		return books;
	}


	
	
	
	public boolean addBook(Book book) {

		try {
				if (bookStorage.getBooks().contains(book)) {
					
					Book b = getBookById(book.getId());
					book.setQuantity(b.getQuantity()+1);
					updateBook(b, book);
					logger.info("Instance of the existing book is added to the BookStorage");
					
				} 
				else 
				{
					book.setQuantity(1);
					book.setReceiptDate(new Date());
					book.setAvailable(true);
					ArrayList <Book>  books = new ArrayList<Book>(bookStorage.getBooks());
					books.add(book);
					bookStorage.setBooks(books);
					logger.trace("Instance of the new book is added to the BookStorage");
				}
			if (EXECUTE_CLAIM){
				for (Claim c : claimStorage.getClaims()) {
				
				if (c.getBook().getId() == book.getId()) {
					c.setExecuted(true);
				}
			}
			}
			return true;
			
		}

		catch (Exception e) {
			logger.error(e.getMessage(),e);
			return false;
		}

	}
	
	public boolean updateBook(Book book1, Book book2){
		book2.setId(book1.getId());
		removeBookById(book1.getId());
		return addBook(book2);
	}
	
	public boolean removeBook(Book book){
		if (getBookById(book.getId()) != null){
			return bookStorage.getBooks().remove(book);
			}
		
			return false;
	}

	public boolean removeBookById(int id) {
		if (getBookById(id) != null){
			return bookStorage.getBooks().remove(getBookById(id));
			}
		
			return false;
	}
	 
	
	public void saveBookListToFile(String file){
		ArrayList<String> res = new ArrayList<String>();
		for (Book b:getBookList()){
			res.add(entityDetails(b));
		}
		try {
			CSVSaver.saveListToFile(file,res);
		} catch (IOException e) {
			logger.error(e.getMessage(), e);
		}
	}
	
	
	public ArrayList<Book> readBooks(String file){
		ArrayList <Book> res = new ArrayList<Book>();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy:MM:dd");
		Date date = new Date();
		
		for (int i = 0; i < CSVReader.readFile(file).length; i++) {
			String book[] = CSVReader.readFile(file)[i].split(Separator.SEPARATOR.getS());
			try {
				date = sdf.parse(book[3]);
			} catch (ParseException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		   	Book b = new Book(Integer.parseInt(book[0]),book[1], book[2],date);
		   	res.add(b);
			
		}
		return res;
	}
	

	
	public static BookStorageService getBookStorageSeviceInstance() {
		if(bookStorageSeviceInstance == null ){
			bookStorageSeviceInstance = new BookStorageService();
		}
		return bookStorageSeviceInstance;
	}
	
	public static String entityDetails(Book t){
		
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy:MM:dd");
		StringBuffer str = new StringBuffer();
		
		str.append(t.getId());
		str.append(Separator.SEPARATOR.getS());		
		str.append(t.getTitle());
		str.append(Separator.SEPARATOR.getS());
		str.append(t.getAuthor());
		str.append(Separator.SEPARATOR.getS());
		str.append(sdf.format(t.getPublicationDate()));
		
		return str.toString();
	}


}
